define([
    'clipboard',
    'angular-loading-bar',
    'angular-toastr.tpls',
    'ng-file-upload-shim',
    'js/factories/dialog'
], function(Clipboard) {
    var utilFactory = angular.module('app.factory.util', ['angular-loading-bar', 'toastr', 'ngFileUpload',
        'app.factory.dialog']);

    utilFactory.factory('xUtil', ['$rootScope', '$q', 'Upload', 'cfpLoadingBar', '$cookies', '$location', '$timeout',
            'xDialog', 'toastr', function($rootScope, $q, Upload, cfpLoadingBar, $cookies, $location, $timeout,
                    xDialog, toastr) {
        return {
            regex: {
                hasKey: function(text, keyword) {
                    var rkeyword = new RegExp('^@' + keyword + '：', 'gmi');
                    return rkeyword.test(text);
                },
                subMatch: function(text, regex) {
                    var match = regex.exec(text);
                    if (match != null && match.length >= 2) {
                        return match[1];
                    }
                    return '';
                },
                keyMatch: function(text, keyword) {
                    var rkeyword = new RegExp('^@' + keyword + '：(((?!\\n@)[^])*)\\n@', 'gmi');
                    return this.subMatch(text, rkeyword).trim();
                },
                urlMatch: function(text, path) {
                    var url = this.subMatch(text, /^@URL：(.*)/gmi).trim();
                    if (url == '') {
                        var dotIndex = path.indexOf('.');//path.lastIndexOf('.');
                        if (dotIndex > 0) {
                            path = path.substring(0, dotIndex);
                        }
                        url = path.replace(/[\w-]+\//, '');
                        if (url.indexOf('/') != 0) {
                            url = '/' + url;
                        }
                    }
                    return url;
                },
                methodMatch: function(text, path) {
                    // From text
                    var method = this.subMatch(text, /^@Method：(.*)/gmi).trim();
                    if (method == '') {
                        // From path
                        method = this.subMatch(path, /\.(get|post|put|patch|delete)\./gi).trim();
                    }
                    if (method) {
                        method = method.toUpperCase();
                    }
                    return method;
                }
            },
            path: {
                join: function(paths) {
                    return this.normalize(paths.join('/'));
                },
                normalize: function(path) {
                    return path.replace(/(\\|\/)+/g, '/');
                }
            },
            file: {
                open: function(file) {
                    return this.upload('/mock/file/read', file);
                },
                save: function(filename, content) {
                    this.download('/mock/file/write', function(jqForm) {
                        jqForm.append($('<input type="hidden">').attr('name', 'filename').val(filename));
                        jqForm.append($('<textarea>').attr('name', 'content').val(content));
                    });
                },
                upload: function(url, file, method) {
                    var defer = $q.defer();
                    // Open file
                    Upload.upload({
                        url: url,
                        method: method || 'POST',
                        data: {
                            'Content-Type': (file.type != '' ? file.type : 'application/octet-stream'),
                            'filename': file.name,
                            'file': file
                        }
                    }).then(function(response) {
                        defer.resolve(response);
                    }, function(data) {
                        defer.reject(data);
                    });
                    return defer.promise;
                },
                download: function(url, jqFormFn) {
                    var jqTargetId = 'jqFormIO-' + (new Date().getTime());
                    var jqForm = $('<form style="display:none">').attr({
                            method: 'POST',
                            action: url,
                            target: jqTargetId
                        }).appendTo(document.body);
                    var jqIframe = $('<iframe style="display:none">').attr({
                            name: jqTargetId
                        }).on('load', function() {
                            var body = $(this).contents().find('body');
                            if (body && body.length > 0) {
                                if (/^0$/.test(body.text())) {
                                    xDialog.open().showSecurity();
                                }
                            }
                        }).appendTo(document.body);
                    // Form data
                    if (typeof(jqFormFn) === 'function') {
                        jqFormFn(jqForm);
                    }

                    // Submit
                    cfpLoadingBar.start();
                    jqForm.submit();

                    // Remove
                    setTimeout(function() {
                        jqForm.remove();
                        jqIframe.remove();
                        cfpLoadingBar.complete();
                    }, 5000);
                }
            },
            testhost: {
                get: function() {
                    return this.list()[0];
                },
                list: function() {
                    var hosts = $cookies.getObject('test_hosts');
                    if (_.isEmpty(hosts)) {
                        return ['http://127.0.0.1:8080'];
                    } else {
                        return hosts;
                    }
                },
                store: function(hosts) {
                    hosts = hosts || [];
                    $cookies.putObject('test_hosts', hosts);
                }
            },
            location: {
                go: function(url) {
                    if (url) {
                        this.history($location.url());
                        $timeout(function() {
                            $location.url(url).replace();
                        });
                    }
                },
                back: function(url) {
                    url = url || this.history();
                    if (url) {
                        this.clear();
                        $timeout(function() {
                            $location.url(url).replace();
                        });
                    }
                },
                history: function(url) {
                    if (url) {
                        $cookies.put('history_url', url);
                    }
                    return $cookies.get('history_url');
                },
                clear: function() {
                    $cookies.remove('history_url');
                }
            },
            clipboard: {
                copy: function(selector, fnText) {
                    var options = {};
                    if (typeof fnText === 'function') {
                        options.text = fnText;
                    }
                    new Clipboard(selector, options).on('success', function(e) {
                        toastr.success('已复制到剪贴板！');
                    });
                }
            },
            mockdoc: {
                parse: function(mockDoc) {
                    var items = {};
                    var ritem = new RegExp('^@([^：]+)：(((?!\\n@)[^])*)', 'gmi');
                    var match = null;
                    // Parse item
                    while ((match = ritem.exec(mockDoc))) {
                        if (match.length > 2) {
                            var item = match[1];
                            var value = (match[2] ? match[2].trim() : '');
                            if (item == 'Method') {
                                value = value.toUpperCase();
                            } else if (item == '出参') {
                                value = value.replace(/^\s*(\*\/|-->)/, '').trim();
                            }
                            items[item] = value;
                        }
                    }
                    return items;
                },
                stringify: function(items, docType) {
                    var mockDoc = (docType == '.xml' ? '<!--' : '/**');
                    // Items to document
                    _.forEach(items, function(value, item) {
                        value = (value || '').trim();
                        mockDoc += '\n@' + item + '：';
                        if (item == '出参') {
                            mockDoc += '\n' + (docType == '.xml' ? '-->' : '*/');
                            mockDoc += '\n' + value;
                        } else {
                            if (item == 'Headers' || item == '入参') {
                                mockDoc += '\n' + value;
                            } else if ((item == '备注' || item == '错误') && value != '') {
                                mockDoc += '\n' + value;
                            } else {
                                mockDoc += value;
                            }
                        }
                    });
                    return mockDoc;
                }
            },
            searchbox: {
                closed: true,
                show: function(editor, context) {
                    var _this = this;
                    var selectedText = editor.getSession().getTextRange(editor.getSelectionRange());
                    if (_this.closed) {
                        _this.closed = false;
                        // Show searchbox
                        xDialog.open().showSearchbox({
                            editor: editor,
                            context: context || selectedText
                        }).then(function(closed) {
                            _this.closed = true;
                        }, function(cancelled) {
                            _this.closed = true;
                        });
                    } else {
                        // Active editor
                        $rootScope.$broadcast('editor.active', editor);
                        // Update search text
                        if (!_.isEmpty(selectedText)) {
                            $rootScope.$broadcast('editor.search', selectedText);
                        }
                    }
                }
            }
        }
    }]);

    return utilFactory;
});
